﻿using System;
using System.Collections.Generic;
using System.Linq;
using FlickrXplorer.Web.ViewData;
using FlickrXplorer.Web.ViewData;
using Linq.Flickr;
using LinqExtender;
using log4net;
using People=FlickrXplorer.Web.ViewData.People;

namespace FlickrXplorer.Web.Models
{
    public class PhotoModel : IPhotoModel
    {
        readonly FlickrContext context = null;
        private readonly ILog log = LogManager.GetLogger("PhotoModel");


        public PhotoModel()
        {
            context = new FlickrContext();
            context.Photos.OnError += new LinqExtender.Query<Linq.Flickr.Photo>.ErrorHandler(ShowException);
            context.Peoples.OnError += new LinqExtender.Query<Linq.Flickr.People>.ErrorHandler(ShowException);
        }

        private void ShowException(ProviderException ex)
        {
            log.Error(ex.Message, ex);
            //throw new Exception(ex.Message, ex);
        }

        public PhotoCollection GetPhotosByTag(string name, int index, int pageLen)
        {
            return GetPhotosByTag(name, TagMode.OR, index, pageLen);
        }

        public People GetPeopleForNsId(string nsId)
        {
            var query = from person in context.Peoples
                        where person.Id == nsId
                        select new People
                        {
                            Username = person.Username,
                            RealName = person.RealName,
                            Id = person.Id,
                            IconUrl = person.IconUrl,
                            Location = person.Location,
                            ProfileUrl = person.ProfileUrl,
                            IsPro = person.IsPro
                        };

            return query.First();
        }

        public PhotoCollection GetPhotosForNsId(string nsId, int index, int pageLen)
        {
            var query = (from ph in context.Photos
                         where
                             ph.PhotoSize == PhotoSize.Square && ph.NsId == nsId
                             select ph).Take(pageLen).Skip(index);

            return BuildPhotoCollection(query.ToList());
        }

        public bool Authenticate()
        {
            try
            {
               if (!string.IsNullOrEmpty(context.Authenticate().Id))
               {
                   return true;
               }
            }
            catch (Exception ex)
            {
                log.Error("Error while athenticating", ex);
                // authentication failed.
            }

            return false;
        }

        public bool IsAuthenticated()
        {
            return context.IsAuthenticated();
        }

        private PhotoCollection GetPhotosByTag(string name, TagMode tagMode, int index, int pageLen)
        {
            var query = (from ph in context.Photos
                         where
                             ph.PhotoSize == PhotoSize.Square && ph.SearchMode == SearchMode.TagsOnly &&
                             ph.SearchText == name && ph.TagMode == tagMode
                             && ph.Extras == (ExtrasOption.Views | ExtrasOption.Tags)
                             && ph.FilterMode == FilterMode.Safe
                         select ph).Take(pageLen).Skip(index);

            return BuildPhotoCollection(query.ToList());
        }

        public PhotoDetail GetPhoto(string photoId)
        {
            var query = from photo in context.Photos
                        where photo.Id == photoId && photo.PhotoSize == PhotoSize.Medium
                        select new PhotoDetail
                        {
                            Id = photo.Id,
                            Description = photo.Description,
                            Title = photo.Title,
                            Url = photo.Url,
                            Username = photo.User,
                            PhotoPage = photo.WebUrl,
                            NsId = photo.NsId,
                            Tags = photo.Tags,
                            UploadedOn = photo.UploadedOn
                        };
            return query.Single();
        }

        public IEnumerable<ViewData.PopularTag> GetPopularTags()
        {
            var query = from tag in context.PopularTags
                        where tag.Count == 10 && tag.Period == TagPeriod.Day
                        orderby tag.Title ascending
                        select new ViewData.PopularTag { Title= tag.Title, Score = tag.Score };

            return query;
        }

        public ViewData.PhotoCollection GetPhotosForKey(string key, bool tagged, int index, int pageLen)
        {
            if (tagged)
                return GetPhotosByTag(key, TagMode.AND, index, pageLen);

            var query = (from ph in context.Photos
                         where ph.PhotoSize == PhotoSize.Square
                            && ph.SearchMode == SearchMode.FreeText
                            && ph.FilterMode == FilterMode.Safe
                            && ph.Extras == (ExtrasOption.Views | ExtrasOption.Tags)
                            && ph.SearchText == key
                         select ph).Take(pageLen).Skip(index);

            return BuildPhotoCollection(query.ToList<Linq.Flickr.Photo>());
        }

        public PhotoCollection GetPhotosByUser(string user, string text, int index, int pageLen)
        {
            var query = (from ph in context.Photos
                         where ph.PhotoSize == PhotoSize.Square && ph.User == user && ph.SearchText == text
                         && ph.Extras == (ExtrasOption.Views | ExtrasOption.Tags)
                         select ph).Take(pageLen).Skip(index);

            return BuildPhotoCollection(query.ToList<Linq.Flickr.Photo>());
        }

        private static PhotoCollection BuildPhotoCollection(IList<Linq.Flickr.Photo> list)
        {
            ViewData.PhotoCollection photoCollection = new PhotoCollection();
            // this way need to be changed.
            if (list.Count > 0)
            {
                photoCollection.Page = list[0].SharedProperty.Page;
                photoCollection.Total = list[0].SharedProperty.Total;
                photoCollection.Pages = list[0].SharedProperty.Pages;
            }

            IEnumerable<ViewData.Photo> photos = list.Select(photo => new ViewData.Photo { Id = photo.Id, Title = photo.Title, Url = photo.Url, Views = photo.ExtrasResult.Views, Tags = photo.Tags});
            
            List<ViewData.Photo> newList = photos.ToList();
            photoCollection.AddRange(newList);

            return photoCollection;
        }

        public People GetPeople(string username)
        {
            var query = from person in context.Peoples
                        where person.Username == username
                        select new People 
                        {
                           Username = person.Username,
                           RealName = person.RealName,
                           Id = person.Id,
                           IconUrl = person.IconUrl,
                           Location = person.Location,
                           ProfileUrl = person.ProfileUrl,
                           IsPro = person.IsPro
                        };

            return query.Single();
        }

        public PhotoCollection GetInterestingPhotos(string category, int index, int pageLen)
        {
            var query = (from ph in context.Photos
                         where ph.PhotoSize == PhotoSize.Square && ph.SearchText == category && ph.FilterMode == FilterMode.Safe
                         && ph.SearchMode == SearchMode.TagsOnly
                         && ph.Extras == (ExtrasOption.Views | ExtrasOption.Tags)
                         orderby PhotoOrder.Interestingness descending
                         select ph).Take(pageLen).Skip(index);

            return BuildPhotoCollection(query.ToList());
        }
    }
}
